package com.zc.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;
import java.time.Duration;

/**
 * @description: 缓存配置
 * @author: cong
 * @create: 2025/2/21
 */
@Configuration
public class CacheConfig {
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> method.getName() + "[" + params[0] + "]";
    }

    /**
     * 配置并创建Redis CacheManager
     * 该方法通过RedisConnectionFactory来构建一个RedisCacheManager实例，并配置缓存的默认过期时间和序列化方式
     *
     * @param factory Redis连接工厂，用于建立与Redis服务器的连接
     * @return CacheManager实例，用于管理缓存
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        ObjectMapper objectMapper = new ObjectMapper();
        // 设置对象所有属性的可见性，使得它们都可以被序列化和反序列化
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 以下行代码已注释掉，作用是启用默认类型检测，但这里选择了更灵活的配置方式
        // objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // 激活默认类型检测，但只针对非final类型，这提高了类型处理的灵活性和安全性
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);

        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);

        // 配置缓存的默认属性
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(10)) // 设置缓存项的过期时间，默认为10分钟
                .disableCachingNullValues()  // 禁止缓存Null值，避免不必要的内存占用
                // 设置键序列化器为StringRedisSerializer，以便将键以字符串形式存储和读取
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(
                        new StringRedisSerializer()))
                // 设置值序列化器为StringRedisSerializer，以便将值以字符串形式存储和读取
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
                        jacksonSerializer));

        // 构建RedisCacheManager实例，使用上述配置
        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
    }

    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
    }
}
